package comment

import (
	"github.com/flipped-aurora/gin-vue-admin/server/global"
	commentModel "github.com/flipped-aurora/gin-vue-admin/server/model/comment"
	commentRequest "github.com/flipped-aurora/gin-vue-admin/server/model/comment/request"
	commonRequest "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
	"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
	systemModel "github.com/flipped-aurora/gin-vue-admin/server/model/system"
	"github.com/flipped-aurora/gin-vue-admin/server/utils"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

type CommentAdminService struct {
}

var CommentAdminServiceApp = new(CommentAdminService)

// GetByFuzzy 根据内容模糊,查询简略信息
func (c *CommentAdminService) GetByFuzzy(ctx *gin.Context, req commonRequest.PageInfo) (resp *response.PageResult, err error) {
	uri := "GetByFuzzy"
	var logID = utils.GetLogID(ctx)

	var comments = make([]commentModel.SysComment, 5)
	var total int64
	// 1. 先统计总条数
	if err = global.GVA_DB.Model(&commentModel.SysComment{}).
		Where("comment_text LIKE ?", "%"+req.Keyword+"%").
		Count(&total).Error; err != nil {
		global.GVA_LOG.Error("统计评论条数失败!",
			zap.String("uri", uri),
			zap.String("log_id", logID),
			zap.String("keyword", req.Keyword),
			zap.Error(err))
		return nil, errors.New("统计条数失败")
	}

	db := global.GVA_DB.Model(&commentModel.SysComment{}).Scopes(req.Paginate()).Where("comment_text like ?", "%"+req.Keyword+"%").
		Select("publisher_id", "comment_text", "created_at", "status").Find(&comments)
	if db.Error != nil {
		global.GVA_LOG.Error("分页查询评论失败!",
			zap.String("uri", uri),
			zap.String("log_id", logID),
			zap.String("keyword", req.Keyword),
			zap.Error(db.Error))
		return resp, errors.New("分页查询失败")
	}

	global.GVA_LOG.Info("模糊查询评论成功",
		zap.String("uri", uri),
		zap.String("log_id", logID),
		zap.String("keyword", req.Keyword),
		zap.Int64("total", total),
		zap.Int("page_size", req.PageSize),
		zap.Int("current_page", req.Page))
	return &response.PageResult{
		List:  comments,
		Total: total,
	}, nil
}

// GetByName 按照用户查询评论,查询简略信息
func (c *CommentAdminService) GetByName(ctx *gin.Context, req commentRequest.GetCommentByUsername) (resp *response.PageResult, err error) {
	uri := "GetByName"
	var logID = utils.GetLogID(ctx)

	var comments = make([]commentModel.SysComment, 5)
	var userIDs []int64
	// 先通过name查询id
	db := global.GVA_DB.Model(&systemModel.SysUser{}).Select("id").Where("username = ?", req.UserName).Find(&userIDs)
	if db.Error != nil {
		global.GVA_LOG.Error("通过用户名查询用户ID失败!",
			zap.String("uri", uri),
			zap.String("log_id", logID),
			zap.String("user_name", req.UserName),
			zap.Error(db.Error))
		return resp, errors.New("通过用户名查询评论失败")
	}
	if len(userIDs) == 0 {
		global.GVA_LOG.Warn("未找到匹配的用户",
			zap.String("uri", uri),
			zap.String("log_id", logID),
			zap.String("user_name", req.UserName))
		return &response.PageResult{List: []commentModel.SysComment{}, Total: 0}, nil
	}
	var total int64
	// 1. 先统计总条数
	if err = global.GVA_DB.Model(&commentModel.SysComment{}).
		Where("publisher_id in ?", userIDs).
		Count(&total).Error; err != nil {
		global.GVA_LOG.Error("统计用户评论条数失败!",
			zap.String("uri", uri),
			zap.String("log_id", logID),
			zap.String("user_name", req.UserName),
			zap.Error(err))
		return nil, errors.New("统计条数失败")
	}
	// 2. 再统计每条的信息
	db = global.GVA_DB.Model(&commentModel.SysComment{}).Scopes(req.Paginate()).Where("publisher_id in ?", userIDs).
		Select("publisher_id", "comment_text", "created_at", "status").Find(&comments)
	if db.Error != nil {
		global.GVA_LOG.Error("通过用户ID查询评论失败!",
			zap.String("uri", uri),
			zap.String("log_id", logID),
			zap.String("user_name", req.UserName),
			zap.Error(db.Error))
		return resp, errors.New("通过用户名查询评论失败")
	}

	global.GVA_LOG.Info("按用户名查询评论成功",
		zap.String("uri", uri),
		zap.String("log_id", logID),
		zap.String("user_name", req.UserName),
		zap.Int64("total", total))
	return &response.PageResult{
		List:  comments,
		Total: total,
	}, nil
}

// GetCommentById 通过comment_id查询评论
func (c *CommentAdminService) GetCommentById(ctx *gin.Context, req commentRequest.GetCommentById) (resp *commentModel.SysComment, err error) {
	uri := "GetCommentById"
	var logID = utils.GetLogID(ctx)

	db := global.GVA_DB.Model(&commentModel.SysComment{}).Where("id = ?", req.CommentId).
		Select("publisher_id", "comment_text", "created_at", "status").Find(&resp)
	if db.Error != nil {
		global.GVA_LOG.Error("通过评论ID查询评论失败!",
			zap.String("uri", uri),
			zap.String("log_id", logID),
			zap.Int64("comment_id", req.CommentId),
			zap.Error(db.Error))
		return resp, errors.New("通过角色id查询用户失败")
	}

	global.GVA_LOG.Info("通过评论ID查询评论成功",
		zap.String("uri", uri),
		zap.String("log_id", logID),
		zap.Int64("comment_id", req.CommentId))
	return resp, nil
}

// DeleteComment 管理员删除评论及其所有子孙（软删除 status = 2）
func (c *CommentAdminService) DeleteComment(ctx *gin.Context, req commentRequest.DeleteAdminCommentId) error {
	uri := "DeleteComment"
	var logID = utils.GetLogID(ctx)

	return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
		// 递归 CTE：查出该评论及其所有子孙 id，一次性把 status 设为 2
		sql := `
		WITH RECURSIVE cte AS (
			SELECT id FROM comment WHERE id = ?
			UNION ALL
			SELECT c.id FROM comment c JOIN cte ON c.parent_comment_id = cte.id
		)
		UPDATE comment SET status = 2 WHERE id IN (SELECT id FROM cte);
		`
		result := tx.Exec(sql, req.CommentId)
		if result.Error != nil {
			global.GVA_LOG.Error("管理员删除评论失败!",
				zap.String("uri", uri),
				zap.String("log_id", logID),
				zap.Int64("comment_id", req.CommentId),
				zap.Error(result.Error))
			return result.Error
		}

		global.GVA_LOG.Info("管理员删除评论成功",
			zap.String("uri", uri),
			zap.String("log_id", logID),
			zap.Int64("comment_id", req.CommentId),
			zap.Int64("affected_rows", result.RowsAffected))
		return nil
	})
}
